﻿/*  CLR版本: 4.0.30319.18063
 * 系统时间: 2014/10/31 14:20:43
 * 创建年份: 2014
 *     作者: 程炜.Snail
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;

namespace Quick.Communicator
{
    /// <summary>
    /// 客户端与服务器之间的会话类
    /// 会话类包含远程通讯端的状态,这些状态包括Socket,报文内容,
    /// 客户端退出的类型(正常关闭,强制退出两种类型)
    /// </summary>
    [Serializable]
    public class Session : ICloneable
    {
        #region 字段
        /// <summary>
        /// 会话ID
        /// </summary>
        private EndPoint _Id;
        /// <summary>
        /// 客户端发送到服务器的报文
        /// 注意:在有些情况下报文可能只是报文的片断而不完整
        /// </summary>
        private string _SpareDatagram;
        /// <summary>
        /// 客户端发送到服务器的报文
        /// 注意:在有些情况下报文可能只是报文的片断而不完整
        /// </summary>
        private byte[] _DatagramByte;
        /// <summary>
        /// 客户端发送到服务器的报文
        /// 注意:在有些情况下报文可能只是报文的片断而不完整
        /// </summary>
        private string _Datagram;
        /// <summary>
        /// 接收客户端的Socket
        /// </summary>
        private SocketAsyncEventArgs _ClientSocketAsyncEventArgs;
        /// <summary>
        /// 客户端的退出类型
        /// </summary>
        private ExitType _ExitType;
        private DateTime _LastConnectionTime;
        private TimeSpan _Timeouts = new TimeSpan(0, 0, 60);
        /// <summary>
        /// 退出类型枚举
        /// </summary>
        public enum ExitType
        {
            NormalExit,
            ExceptionExit
        };
        #endregion
        #region 属性
        /// <summary>
        /// 超时判定时间
        /// </summary>
        public TimeSpan Timeouts
        {
            get { return _Timeouts; }
            set { _Timeouts = value; }
        }
        /// <summary>
        /// 最后一次连接时间
        /// </summary>
        public DateTime LastConnectionTime
        {
            get { return _LastConnectionTime; }
            set { _LastConnectionTime = value; }
        }
        private DateTime _ConnectionTime;
        /// <summary>
        /// 连接时间
        /// </summary>
        public DateTime ConnectionTime
        {
            get { return _ConnectionTime; }
        }
        /// <summary>
        /// 返回会话的ID
        /// </summary>
        public EndPoint ID
        {
            get
            {
                return _Id;
            }
        }
        /// <summary>
        /// 剩下的会话报文
        /// </summary>
        public string SpareDatagram
        {
            get
            {
                return _SpareDatagram;
            }
            set
            {
                _SpareDatagram = value;
            }
        }
        /// <summary>
        /// 当前获取到的报文字节数组(已经分包处理)
        /// </summary>
        public byte[] DatagramByte
        {
            get
            {
                return _DatagramByte;
            }
            set
            {
                _DatagramByte = value;
            }
        }
        /// <summary>
        /// 当前获取到的报文字符串(已经分包处理)
        /// </summary>
        public string Datagram
        {
            get
            {
                return _Datagram;
            }
            set
            {
                _Datagram = value;
            }
        }
        /// <summary>
        /// 获得与客户端会话关联的接收数据Socket对象
        /// </summary>
        public SocketAsyncEventArgs ClientSocketAsyncEventArgs
        {
            get
            {
                return _ClientSocketAsyncEventArgs;
            }
        }
        /// <summary>
        /// 存取客户端的退出方式
        /// </summary>
        public ExitType TypeOfExit
        {
            get
            {
                return _ExitType;
            }
            set
            {
                _ExitType = value;
            }
        }
        #endregion
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="receiveCliSock">会话使用的Socket[接收数据]连接(超时分钟数默认设置为10分钟)</param>
        public Session(SocketAsyncEventArgs receiveCliSock)
        {
            //Debug.Assert(cliSock != null);
            this._ConnectionTime = DateTime.Now;
            this._LastConnectionTime = DateTime.Now;
            _ClientSocketAsyncEventArgs = receiveCliSock;
            Socket sck = (Socket)receiveCliSock.UserToken;
            if (sck.Connected)
            {
                _Id = sck.RemoteEndPoint;
            }
            else
            {
                _Id = receiveCliSock.RemoteEndPoint;
            }
            this._Timeouts = new TimeSpan(0, 10, 0);
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="receiveCliSock">会话使用的Socket连接</param>
        /// <param name="timeouts">超时分钟数</param>
        public Session(SocketAsyncEventArgs receiveCliSock, int timeouts)
        {
            Debug.Assert(receiveCliSock != null);
            this._ConnectionTime = DateTime.Now;
            this._LastConnectionTime = DateTime.Now;
            _ClientSocketAsyncEventArgs = receiveCliSock;
            _Id = (receiveCliSock.UserToken as Socket).RemoteEndPoint;
            this._Timeouts = new TimeSpan(0, timeouts, 0);
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public Session(EndPoint endPoint, int timeouts)
        {
            _Id = endPoint;
            this._ConnectionTime = DateTime.Now;
            this._LastConnectionTime = DateTime.Now;
            this._Timeouts = new TimeSpan(0, timeouts, 0);
        }
        ///// <summary>
        ///// 关闭会话
        ///// </summary>
        //public void Close()
        //{
        //    this._SpareDatagram = null;
        //    this._DatagramByte = null;
        //    //关闭数据的接受和发送
        //    Socket sck = _ClientSocketAsyncEventArgs.UserToken as Socket;
        //    sck.Shutdown(SocketShutdown.Both);
        //    //清理资源
        //    sck.Close();
        //}
        #region ICloneable 成员
        object System.ICloneable.Clone()
        {
            Session newSession = null;
            if (null == _ClientSocketAsyncEventArgs)
            {
                newSession = new Session(this.ID, this.Timeouts.Minutes);
            }
            else
            {
                newSession = new Session(_ClientSocketAsyncEventArgs, this._Timeouts.Minutes);
            }
            newSession.DatagramByte = this._DatagramByte;
            newSession.TypeOfExit = _ExitType;
            return newSession;
        }
        #endregion
    }
}
